# Copyright (C) 2008, Mads D. Kristensen
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import sys
from PyQt4 import uic, QtGui
from PyQt4.QtCore import *
from xmlrpclib import ServerProxy
from uuid import uuid4

class ScavengerTestingApp(QtGui.QApplication):
    """GUI app for testing execution of mobile code on a Scavenger host."""
    def __init__(self):
        super(QtGui.QApplication, self).__init__(sys.argv)
        
        # Create XMLRPC things.
        self.scavenger_rpc = None
        
        # Load the GUI.
        self.main_window = uic.loadUi('mainwindow.ui')
        
        # Connect signals to the buttons.
        self.connect(self.main_window.checkConnectionButton, SIGNAL("clicked()"), self.checkConnectionClicked)
        self.connect(self.main_window.performButton, SIGNAL("clicked()"), self.performClicked)
        
        # Set properties of the text edits.
        self.main_window.codeTextEdit.setTabStopWidth(20)
        self.main_window.codeTextEdit.document().setDefaultFont(QtGui.QFont('courier', 12))
        self.main_window.resultTextEdit.document().setDefaultFont(QtGui.QFont('courier', 12))
        self.main_window.codeTextEdit.setText(ScavengerTestingApp.STD_CODE)
        
        # Show the main window.
        self.main_window.show()
        
    def checkConnectionClicked(self):
        try:
            host_address = 'http://' + self.main_window.scavengerHostLineEdit.text() +\
                           ':' + self.main_window.scavengerPortLineEdit.text()
            self.scavenger_rpc = ServerProxy(str(host_address))
            self.scavenger_rpc.ping(True)
            self.main_window.resultTextEdit.setText("Successfully established a connection to the Scavenger host.")
        except Exception, e:
            self.main_window.resultTextEdit.setText('Error establishing a connection to %s\n\n%s\n%s'%\
                                                   (host_address, str(e), str(e.args)))
    
    def __printError(self, msg, error):
        text = '%s\n%s\nFault code: "%s"\nFault string: "%s"'%(msg, '-'*len(msg), error.faultCode, error.faultString)
        self.main_window.resultTextEdit.setText(text)
    
    def performClicked(self):
        # Set the address of the scavenger host.
        host_address = 'http://' + self.main_window.scavengerHostLineEdit.text() +\
                       ':' + self.main_window.scavengerPortLineEdit.text()
        self.scavenger_rpc = ServerProxy(str(host_address))
        
        # Create a unique service name.
        service_name = 'hack.attack.' + uuid4().hex
        try:
            while self.scavenger_rpc.has_service(service_name):
                service_name = 'hack.attack.' + uuid4().hex
        except Exception, e:
            self.__printError('Error creating service name:', e)
            return
            
        # Install the service.
        try:
            self.scavenger_rpc.install_service(service_name, str(self.main_window.codeTextEdit.toPlainText()))
        except Exception, e:
            self.__printError('Error installing service:', e)
            return

        # Perform the service.
        try:
            result = self.scavenger_rpc.perform_service(service_name, {}, 10)
            self.main_window.resultTextEdit.setText('Service performed, output was:\n------------------------------\n%s'%str(result))
        except Exception, e:
            self.__printError('Error performing service:', e)
            return
            
    STD_CODE = """# Insert code, import statements, etc. here.

def perform(_):
\t# This function will be performed when the code is shipped to the server.
\tpass

\t# A service _must_ return something - otherwise XMLRPC will fail.
\treturn 0
"""
    
if __name__ == '__main__':
    # Create the GUI app.
    app = ScavengerTestingApp()
    
    rc = app.exec_()
    
    sys.exit(rc)